#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include ".\miniz\miniz.h"
#include <unistd.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

#define LINE_MAX_BYTES (16 * 1024)
#define COMPRESS_HEADER "Coros Header "
#define COMPRESS_HEADER_2 "crhd"

#define COMPRESS_HEADER_NUMBER_LEN 6
#define COMPRESS_DATA_OFFSET 19

#if 0
#define logs_printf printf
#else
#define logs_printf(...)
#endif

typedef struct
{
	char path[256];
} path_info_t;

typedef struct
{
	uint8_t checksum;		// meas_data校验和
	uint16_t datagroup;		// rawdata组数
	uint8_t channel;		// 通道数
	uint8_t data_width : 4; // 原始数据字节宽度
	uint8_t version : 4;
	uint32_t reserve[2];
	char rawdata_buff[0];
} __attribute__((packed)) senser_raw_t;

char hex2char(char hex)
{
	return hex - 0x30;
}

int compress_packsize = 512;
int check_unexpect_char(char *p_string, int len)
{
	int ret = 1;
	for (int i = 0; i < len; i++)
	{
		if (p_string[i] >= 'a' && p_string[i] <= 'z')
		{
			ret = 0;
			break;
		}
		if (p_string[i] >= 'A' && p_string[i] <= 'Z')
		{
			ret = 0;
			break;
		}
		if (p_string[i] >= 'A' && p_string[i] <= 'Z')
		{
			ret = 0;
			break;
		}
		if (p_string[i] == '=' || p_string[i] == '>' || p_string[i] == '<')
		{
			ret = 0;
			break;
		}
	}

	return ret;
}
int get_compress_header_len(char *line)
{
	const int len_offset = COMPRESS_DATA_OFFSET - COMPRESS_HEADER_NUMBER_LEN;
	int len_cal = hex2char(line[len_offset]) * 1 * 100000 +
				  hex2char(line[len_offset + 1]) * 1 * 10000 +
				  hex2char(line[len_offset + 2]) * 1 * 1000 +
				  hex2char(line[len_offset + 3]) * 1 * 100 +
				  hex2char(line[len_offset + 4]) * 1 * 10 +
				  hex2char(line[len_offset + 5]) * 1 * 1;
	return len_cal;
}

void get_compress_data(char *pack, int pack_size, char *compress_data)
{
	memcpy(compress_data, &pack[COMPRESS_DATA_OFFSET], pack_size);
	return;
}

void get_decompress_file_name(char *file_name, int name_len, char *name_out_put)
{
	int dot_index = 0;
	(void)name_len;
	for (int i = 0; i < (int)strlen(file_name); i++)
	{
		if (file_name[i] == '.')
		{
			dot_index = i;
		}
	}

	if (dot_index)
	{
		memcpy(name_out_put, &file_name[0], dot_index);
		snprintf(&name_out_put[dot_index], 20, "_decode.txt");
	}
	return;
}

void help_printf(void)
{
	printf("---------------help------------\r\n");
	printf("\"decompress.exe [path] [package size]\"\r\n");
	printf("eg: \"decompress.exe log_sport_7e0285_20240312_201617_0_decode.txt 512\"\r\n");
	printf("---------------help------------\r\n\r\n\r\n");
}

void rawdata_write_file(FILE *fp, char *data_header, int data_width,
						char *rawdata_buff, int data_group, int data_channel)
{
	if (data_width == 4)
	{
		int *p_rawdata = (int *)rawdata_buff;
		for (int i = 0; i < data_group; i++)
		{
			char temp_buff[1024] = {0};

			strcat(temp_buff, data_header); // 每行加头
			for (int j = 0; j < data_channel; j++)
			{
				char raw_hex_string[64] = {0};
				if (j < data_channel - 1)
				{
					snprintf(raw_hex_string, sizeof(raw_hex_string), "%d ", p_rawdata[i * data_channel + j]);
				}
				else
				{
					snprintf(raw_hex_string, sizeof(raw_hex_string), "%d\r\n", p_rawdata[i * data_channel + j]);
				}
				strcat(temp_buff, raw_hex_string);
			}
			logs_printf("c=%s", temp_buff);
			fwrite(temp_buff, 1, strlen(temp_buff), fp);
		}
	}
	else if (data_width == 2)
	{
		short int *p_rawdata = (short int *)rawdata_buff;
		for (int i = 0; i < data_group; i++)
		{

			char temp_buff[1024] = {0};

			strcat(temp_buff, data_header); // 每行加头
			for (int j = 0; j < data_channel; j++)
			{
				char raw_hex_string[64] = {0};
				if (j < data_channel - 1)
				{
					snprintf(raw_hex_string, sizeof(raw_hex_string), "%d ", p_rawdata[i * data_channel + j]);
				}
				else
				{
					snprintf(raw_hex_string, sizeof(raw_hex_string), "%d\r\n", p_rawdata[i * data_channel + j]);
				}
				strcat(temp_buff, raw_hex_string);
			}
			logs_printf("c=%s", temp_buff);
			fwrite(temp_buff, 1, strlen(temp_buff), fp);
		}
	}
}
void file_decode_or(char *path, uint8_t key)
{
	char file_decode_or_name[256] = {0};
	memcpy(file_decode_or_name, path, strlen(path) - 3);
	int temp = 0;

	temp = strlen(file_decode_or_name);
	memcpy(&file_decode_or_name[temp], "txt", 3);
	logs_printf("file_decode_or_name=%s\r\n", file_decode_or_name);

	FILE *file_output = fopen(file_decode_or_name, "wb");
	FILE *file_input = fopen(path, "rb");

	while (1)
	{
		char pack_buff[4096] = {0};
		int pack_size = 4096;
		int read_size = 0;
		read_size = fread(pack_buff,
						  1,
						  pack_size,
						  file_input);
		if (read_size == 0)
		{
			break;
		}

		char buff_decode[4096] = {0};
		for (int i = 0; i < read_size; i++)
		{
			buff_decode[i] = pack_buff[i] ^ key;
		}
		fwrite(buff_decode, 1, read_size, file_output);
	}
	fclose(file_output);
	fclose(file_input);
}
void sensor_file_decode(char *path)
{
	FILE *file_input = fopen(path, "rb+");

	char line[LINE_MAX_BYTES];
	int last_pos = 0;
	char decompress_file_name[128] = {0};
	get_decompress_file_name(path, strlen(path), decompress_file_name);
	FILE *file_output = fopen(decompress_file_name, "wb");

	while (1)
	{
		memset(line, 0, sizeof(line));
		last_pos = ftell(file_input);

		if (fgets(line, sizeof(line), file_input) == 0)
		{
			break;
		}
		// logs_printf("line=%s,%d\r\n", line, strlen(line));

		if (memcmp(line, COMPRESS_HEADER, strlen(COMPRESS_HEADER)) == 0)
		{
#if 0
				fseek(file_output, -2, SEEK_CUR); // 过滤协议里COROS HEADER前面的换行
	
				int compress_len = get_compress_header_len(line);
				fseek(file_input, last_pos, SEEK_SET); // 回到读该行之前的位置
	
				char pack_buff[4096] = {0};
				int pack_size = compress_len + strlen(COMPRESS_HEADER) + COMPRESS_HEADER_NUMBER_LEN;
				fread(pack_buff,
					  1,
					  pack_size,
					  file_input);
	
				// 从文件提取压缩后的数据
				char compress_data[4096] = {0};
				get_compress_data(pack_buff, pack_size, compress_data);
				// logs_printf("%s", pack_buff);
	
				// 将压缩后的数据解压
	
				int depress_len = compressBound(compress_packsize);
				char *depress_buff = malloc(depress_len);
				memset(depress_buff, 0, depress_len);
				int ret = 0;
				ret = uncompress((unsigned char *)depress_buff,
								 (unsigned long *)&depress_len,
								 (const unsigned char *)compress_data,
								 (unsigned long)compress_len);
	
				if (ret)
				{
					printf("error %d\r\n", ret);
				}
				logs_printf("depress data=%s", depress_buff);
				fwrite(depress_buff, 1, depress_len, file_output);
				free(depress_buff);
#endif
		}
		else if (strstr(line, COMPRESS_HEADER_2))
		{
			fseek(file_output, -2, SEEK_CUR); // 过滤协议里COROS HEADER前面的换行
			char *p_temp = strstr(line, COMPRESS_HEADER_2);
			int offset_header = p_temp - line;
			char data_header[20] = {0}; // 每一行的标签头
			memcpy(data_header, line, offset_header);

			fseek(file_input, last_pos + offset_header, SEEK_SET); // 回到读该行之前的位置

			int data_buff_size = sizeof(senser_raw_t) + strlen(COMPRESS_HEADER_2);

			char *data_buff = malloc(data_buff_size);
			fread(data_buff, 1, data_buff_size, file_input);
			senser_raw_t *senser_raw = (senser_raw_t *)&data_buff[strlen(COMPRESS_HEADER_2)];
			// printf("channel %d datagroup %d\r\n", senser_raw->channel, senser_raw->datagroup);

			int rawdata_buff_len = senser_raw->data_width * senser_raw->datagroup * senser_raw->channel;
			char *rawdata_buff = malloc(rawdata_buff_len);
			fread(rawdata_buff, 1, rawdata_buff_len, file_input);
			rawdata_write_file(file_output, data_header, senser_raw->data_width, rawdata_buff,
							   senser_raw->datagroup, senser_raw->channel);
			free(data_buff);
			free(rawdata_buff);
		}
		else
		{
			fwrite(line, 1, strlen(line), file_output);

			//			char test_string[128]="1111\r\n2222";
			//			fwrite(test_string,1,strlen(test_string),file_output);
		}
		// logs_printf("%s", line);
	}

	fclose(file_input);
	fclose(file_output);
	// printf("finish\r\n");
}

void read_dir_files(path_info_t *file_path, int max_count, int *read_count)
{
	DIR *dir;
	struct dirent *entry;
	int index = 0;

	// 打开当前目录
	if ((dir = opendir(".")) != NULL)
	{
		while ((entry = readdir(dir)) != NULL)
		{
			if (index < max_count)
			{
				memcpy(file_path[index].path, entry->d_name, strlen(entry->d_name));
				index++;
			}
			logs_printf("%s\n", entry->d_name);
		}
		closedir(dir);
	}
	if (read_count)
	{
		*read_count = index;
	}
	return;
}

unsigned char check_sum(unsigned char *p_data, unsigned int length)
{
	unsigned char sum = 0;
	unsigned int i;

	for (i = 0; i < length; i++)
	{
		sum += *(p_data + i);
	}

	return sum;
}

void get_device_id(char *path, char *id_info)
{
	int catch_flag = 0;

	int catch_index = 0;
	for (int i = 0; i < (int)strlen(path); i++)
	{
		if (path[i] == '_')
		{
			catch_flag++;
		}
		if (catch_flag == 2)
		{
			catch_index = i;
			break;
		}
	}
	if (id_info)
	{
		memcpy(id_info, &path[catch_index + 1], 6);
	}
}

int main(int argc, char *argv[])
{
	// help_printf();
	//  取输入路径
	if (argc > 1)
	{
		printf("argv=%s\r\n", argv[1]);
	}
	if (argc > 2)
	{
		char *endptr;

		compress_packsize = strtol(argv[2], &endptr, 10);
	}

	const int max_search_count = 100;
	int real_count = 0;
	path_info_t file_search[max_search_count];
	memset(file_search, 0, sizeof(file_search));
	read_dir_files(file_search, max_search_count, &real_count);

	printf("real_count=%d\r\n", real_count);

	// 异或解码
	for (int i = 0; i < real_count; i++)
	{
		if (strstr(file_search[i].path, ".dat") == NULL || strstr(file_search[i].path, "log_") == NULL)
		{
			continue;
		}
		char id_info[64] = {0};
		get_device_id(file_search[i].path, id_info);
		uint8_t key = check_sum((unsigned char *)id_info, 6);
		printf("decode or,id_info=%s key=0x%x\r\n", id_info, key);
		file_decode_or(file_search[i].path, key);
	}

	// sensor data协议解码
	memset(file_search, 0, sizeof(file_search));
	read_dir_files(file_search, max_search_count, &real_count);
	for (int i = 0; i < real_count; i++)
	{
		if (strstr(file_search[i].path, ".txt") == NULL ||
			strstr(file_search[i].path, "log_") == NULL)
		{
			continue;
		}
		if (strstr(file_search[i].path, "decode"))
		{
			continue;
		}
		printf("decode sensor daata,file=%s\r\n", file_search[i].path);
		sensor_file_decode(file_search[i].path);
		unlink(file_search[i].path);
	}
	printf("done\r\n");
	sleep(3);
	return 0;
}
